// Copyright  2012 Petr TALLA. [petr.talla@gmail.com]
// This file is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License
// as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This file is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY;  without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU Lesser General Public License for more details.
// [http://www.gnu.org/copyleft/lesser.html]
//=============================================================================

package tc.crase.view;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Stroke;
import java.awt.geom.Point2D;
import java.util.Hashtable;

import javax.swing.UIManager;

import tc.common.display.Display;
import tc.common.display.GentityConnector;
import tc.common.display.GentityText;
import tc.common.registry.Ref;
import tc.common.registry.RegistrySys;
import tc.common.registry.Rview;
import tc.common.utility.GrObject;
import tc.common.utility.GrView;
import tc.common.utility.TcDisplayXY;
import tc.common.utility.Vector2D;

import tc.crase.db.Xattr;
import tc.crase.db.XattrGIT;
import tc.crase.db.XattrGRP;
import tc.crase.db.XattrGXY;
import tc.crase.db.XattrLNK;
import tc.crase.db.Xdb;
import tc.crase.db.Xobject;
import tc.common.symbology.SfeatArea;
import tc.common.symbology.SfeatLine;
import tc.common.symbology.Style;
import tc.common.symbology.Symbol;
import tc.crase.sys.XdbEx;
import tc.crase.sys.XobjectEx;

public class GrDocGraph extends GrObject implements Rview {
	public Ref doc;
	ViewGraph  view;

	public GrDocGraph (XobjectEx graph, ViewGraph view) {
		super("undefined");
		
		RegistrySys.registry.views.add(this);
		doc = new Ref(graph.objex, this);
		this.view = view;
	}
	
	public XattrGRP getDocGraph() {
		XobjectEx.ObjEx objex = (XobjectEx.ObjEx)doc.original;
		XobjectEx xobjex = objex.getObject();
		
		for (Xattr attr : xobjex) {
			XattrGRP attrGrp = attr.getAsGRP();
			if (attrGrp == null) continue;
			return attrGrp;
		}
		
		XattrGRP result = new XattrGRP(-1, xobjex);
		xobjex.attrAdd(result);
		return result;
	}
	
	public void toDisplay(Display display) {
		Hashtable<Integer, GentityText> boxes = new Hashtable<Integer, GentityText>();
		
		toDisplayObjects( display, boxes);
		toDisplayLinks( display, boxes);
		toDisplayLinksGraph( display, boxes);
	}
	
	public void toDisplayLinksGraph(Display display, Hashtable<Integer, GentityText> boxes) {
		XattrGRP attrGraph1 = getDocGraph();
		
		for ( XattrGIT item1 : attrGraph1 ) {
			if (item1 == null) continue;
				
			XobjectEx object1 = (XobjectEx)item1.getParent();
			
			for (Xattr attr : object1) {
				XattrGRP attrGraph = attr.getAsGRP();
				if (attrGraph == null) continue;
				
				for ( XattrGIT item : attrGraph ) {
					if (item == null) continue;
					
					XobjectEx object2 = (XobjectEx)item.getParent();
					for (Xattr attr2 : object2) {
						XattrGXY attrGxy2 = attr2.getAsGXY();
						if (attrGxy2 == null) continue;
												
						if (attrGxy2.getGroup() != attrGraph1) continue;
					
						GentityConnector connector = new GentityConnector(boxes.get(object1.objex.obid),
							                                          boxes.get(object2.objex.obid));
						display.add(connector);
					}
				}
			}
		}		
	}
	
	public void toDisplayLinks(Display display, Hashtable<Integer, GentityText> boxes) {
		XattrGRP attrGraph = getDocGraph();
		
		for ( XattrGIT item1 : attrGraph ) {
			if (item1 == null) continue;
				
			XattrGXY itemXY1 = item1.getAsGXY();
			Xobject object1 = itemXY1.getParent();
		
			for ( Xattr attr : object1 ) {
				if (attr == null) continue;
				XattrLNK lnk1 = attr.getAsLNK();
				
				if (lnk1 == null) continue;
				if (lnk1.isFirst() == false) continue;
				
				XattrLNK lnk2 = lnk1.getOpposite();
				Xobject object2 = lnk2.getParent();
				
				for (Xattr attr2 : object2) {
					XattrGXY itemXY2 = attr2.getAsGXY();
					if (itemXY2 == null) continue;
					if (itemXY2.getGroup() != attrGraph) continue;

					toDisplayLink(display, lnk1, lnk2, boxes);
				}
				
				/*for (XattrGIT item2 : attrGraph) {
					if ( item2 == null ) {
						//g.drawString("BROAKEN LINK FOUND", 200, 200);
						continue;
					}
					if (item2 instanceof XattrGXY == false) continue; 
					
					XattrGXY itemXY2 = (XattrGXY)item2;
					
					XobjectEx object2 = (XobjectEx)itemXY2.getParent();
					XattrLNK lnk2 = lnk1.getOpposite();
					if (lnk2 == null) continue;
					XobjectEx object1 = (XobjectEx)lnk1.getParent();
					if (object2 != object1) continue;
					
					toDisplayLink(display, lnk1, lnk2, boxes);
				}*/
			}
		}		
	}
	
	public void toDisplayLink(Display display, XattrLNK lnk1, XattrLNK lnk2, Hashtable<Integer, GentityText> boxes) {
		GentityConnector connector;
		
		XobjectEx object1 = (XobjectEx)lnk1.getParent();
		XobjectEx object2 = (XobjectEx)lnk2.getParent();
		
		Style styleLnk = getStyleLink(lnk1);
		if (styleLnk != null) {
			connector = new GentityConnector(boxes.get(object1.objex.obid), boxes.get(object2.objex.obid));
			connector.style = styleLnk;
		}
		else {
			styleLnk = getStyleLink(lnk1.getOpposite());
			if (styleLnk != null) {
				connector = new GentityConnector(boxes.get(object2.objex.obid), boxes.get(object1.objex.obid));
				connector.style = styleLnk;
			}
			else {
				connector = new GentityConnector(boxes.get(object1.objex.obid), boxes.get(object2.objex.obid));
				connector.text1 = lnk1.getName();
				connector.text2 = lnk2.getName();
			}
		}
		
		display.add(connector);
	}
	
	public void toDisplayObjects(Display display, Hashtable<Integer, GentityText> boxes) {
		XattrGRP attrGraph = getDocGraph();
		
		for ( XattrGIT item : attrGraph ) {
			if (item == null) continue;
				
			XattrGXY itemXY = item.getAsGXY();
			
			XobjectEx xobjex = (XobjectEx)itemXY.getParent();
			
			String text = xobjex.formatTypes() + ": " + Formatter.shortFormat(xobjex);
			
			GentityText gentity = new GentityText(text, itemXY.xy);
			if (xobjex.getSelected()) gentity.selected = true;
						
			gentity.style = getStyle(xobjex);
			display.add(gentity);
			boxes.put(xobjex.objex.obid, gentity);
		}
	}
	
	public Style getStyleLink(XattrLNK lnk) {
		String linkid = lnk.getName() + "-" + lnk.getOpposite().getName();
		
		Style style = null;
		
		Xdb xdb = lnk.getParent().getDb();
		if (xdb instanceof XdbEx) {
			XdbEx xdbex = (XdbEx)xdb;
			style = (Style)xdbex.metadata.legend.styles.get(linkid);
		}
		
		return style;
	}
	
	public Style getStyle(XobjectEx object) {
		Style style = null;
		
		Xdb xdb = object.getDb();
		if (xdb instanceof XdbEx) {
			XdbEx xdbex = (XdbEx)xdb;
			style = (Style)xdbex.metadata.legend.styles.get(object.getType());
		}
		
		return style;
	}
	
	public void display(Graphics g, GrView view) {
		Display display = new Display();
		toDisplay(display);
		display.display(g, view.transf);
	}
	
	public boolean getDirty() {return view.dirty; };
	public void setDirty(boolean value) { if (value == false) return; view.dirty = value;};
	public void checkPresence() {
		setDirty(true);
		return;
	}
	public void updateRview() {};
	public void onRefChanged(Ref ref) {};
}


























/*private void displayLinks(Graphics g, XattrGXY itemXY, TcDisplayXY XY, GentityText.ObjectRectangle rect1) {
XattrGRP attrGraph = getDocGraph();

//<STEP> display links
for ( Xattr attr : itemXY.getParent() ) {
	if (attr == null) continue;
	XattrLNK lnk = attr.getAsLNK();
	if (lnk == null)
		continue;
	if (lnk.isFirst() == false)
		continue;
	
	for (XattrGIT attrGit : attrGraph) {
		if ( attrGit == null ) continue;
		if (attrGit instanceof XattrGXY == false) continue; 
		
		XattrGXY itemXY2 = (XattrGXY)attrGit;
		
		XobjectEx object2 = (XobjectEx)itemXY2.getParent();
		XattrLNK lnkOpposite = lnk.getOpposite();
		if (lnkOpposite == null) continue;
		if (object2 == lnkOpposite.getParent()) {
			TcDisplayXY XY2 = new TcDisplayXY(itemXY2.xy,
					view.transf, TcDisplayXY.CoordSys.WORLD);
			XY2.transform(TcDisplayXY.CoordSys.DEVICE);
			
			Style style2 = getStyle(object2);
			
			GentityText.ObjectRectangle rect2 = GentityText.getObjectRectangle(g, null, XY2.xy, style2);
			
			Style styleLnk = getStyleLink(lnk);
			if (styleLnk != null) {
				displayLinkStyled(g, styleLnk, XY.xy, XY2.xy, rect1, rect2);
			}
			else {
				styleLnk = getStyleLink(lnk.getOpposite());
				if (styleLnk != null) {
					displayLinkStyled(g, styleLnk, XY2.xy, XY.xy, rect2, rect1);
				}
				else {
					displayLink(g, lnk, XY.xy, XY2.xy, rect1, rect2);
				}
			}
		}
	}
}		
}*/

/*private String getObjectcontent(XattrGXY itemXY) {
	XobjectEx xoEx = (XobjectEx)itemXY.getParent();
	return xoEx.formatTypes() + ": " + Formatter.shortFormat(xoEx);
}*/

/*public GentityText.ObjectRectangle displayObject(Graphics g, GrView view, XattrGXY itemXY, TcDisplayXY XY, Style style) {
Font oldFont = g.getFont();
Color oldColor = g.getColor();
g.setFont(GentityText.fontObject);

String content = getObjectcontent(itemXY);

GentityText.ObjectRectangle r = GentityText.getObjectRectangle(g, content, XY.xy, style);

XobjectEx xobjEx = (XobjectEx)itemXY.getParent();

if (xobjEx.getSelected()) {
	ViewRoot.styleSelected.drawRect( g, r.x, r.y, r.width, r.height, 12);
}
		
if (style != null) {
	style.drawRect( g, r.x, r.y, r.width, r.height, GentityText.SHAPE_OFFSET);
}

g.setColor(oldColor);
g.drawString(content, r.x, r.y + r.ascent);

g.setFont(oldFont);

return r;
}*/

/*private boolean displayLinkShortenDecision(int d0, int d1, int d2, int d3) {
if (d0 < d1) return false;
if (d0 < d2) return false;
if (d0 < d3) return false;
return true;
}

private void displayLinkShorten(GentityText.ObjectRectangle r, GentityText.ObjectRectangle r2, Point2D.Double xy, Point2D.Double xy2) {
int left  = r.x - (r2.x+r2.width);
int right = r2.x - (r.x+r.width); 

int up  = r.y - (r2.y+r2.height);
int down = r2.y - (r.y+r.height);

up -= up/3;
down -= down/3;

if (displayLinkShortenDecision(left, right, up, down) ) {
	xy.x = r.x-r.offset;
}
else if (displayLinkShortenDecision(right, left, up, down) ) {
	xy.x = r.x+r.width+r.offset;
}
else if (displayLinkShortenDecision(up, left, right, down) ) {
	xy.y = r.y-r.offset;
}
else {
	xy.y = r.y+r.height+r.offset;
}
}*/

/*	private void displayLinkStyled(Graphics g, Style style, Point2D.Double xy1, Point2D.Double xy2, GentityText.ObjectRectangle r1, GentityText.ObjectRectangle r2) {
displayLinkShorten(r1, r2, xy1, xy2);
displayLinkShorten(r2, r1, xy2, xy1);

Graphics2D g2 = (Graphics2D)g;
Stroke oldStroke = g2.getStroke();
g2.setStroke(new BasicStroke(2.0F));

g2.drawLine((int) xy1.x, (int) xy1.y, (int) xy2.x, (int) xy2.y);

for (int i = 0; i < style.sfeats.size(); i++ ) {
	SfeatLine sfLine = style.sfeats.get(i).getAsLine();
	if (sfLine == null) continue;
	
	if (sfLine.symbolBegin != null) {
		sfLine.symbolBegin.displayRot(g, (int)xy1.x, (int)xy1.y, -12, 0, 
				Symbol.DIM*2/24, Symbol.DIM*2/24, (int)(xy2.x-xy1.x), (int)(xy2.y-xy1.y));
	}
	
	if (sfLine.symbolEnd != null) {
		sfLine.symbolEnd.displayRot(g, (int)xy2.x, (int)xy2.y, 12, 0, 
				Symbol.DIM*2/24, Symbol.DIM*2/24, (int)(xy2.x-xy1.x), (int)(xy2.y-xy1.y));
	}
}

g2.setStroke(oldStroke);
}*/

/*	private void displayLink(Graphics g, XattrLNK lnk, Point2D.Double xy1, Point2D.Double xy2, GentityText.ObjectRectangle r1, GentityText.ObjectRectangle r2) {
displayLinkShorten(r1, r2, xy1, xy2);
displayLinkShorten(r2, r1, xy2, xy1);

g.drawLine((int) xy1.x, (int) xy1.y, (int) xy2.x,
		(int) xy2.y);

Vector2D dir = new Vector2D(xy1, xy2);

Font oldf = g.getFont();
g.setFont(GentityConnector.fontLink);

dir.multiply(0.33333);

Point2D.Double p0 = new Point2D.Double(xy1.x, xy1.y);
dir.addTo(p0);

Point2D.Double p1 = new Point2D.Double(xy1.x, xy1.y);
dir.multiply(2.0);
dir.addTo(p1);

g.drawString(lnk.getName(), (int)p0.x, (int)p0.y);
g.drawString(lnk.getOpposite().getName(), (int)p1.x, (int)p1.y);

g.setFont(oldf);
}*/
